﻿using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using EasyXaf.EntityDesigner.BusinessObjects.Entities.EntityProperties;
using System.ComponentModel;
using System.Reflection;

namespace EasyXaf.EntityDesigner.Tools.Extensions;

public static class MemberInfoExtensions
{
    public static string GetName(this IMemberInfo memberInfo)
    {
        return memberInfo.Name;
    }

    public static string GetCaption(this MemberInfo memberInfo)
    {
        var attribute1 = memberInfo.GetCustomAttribute<System.ComponentModel.DisplayNameAttribute>(false);
        if (attribute1 != null)
        {
            return attribute1.DisplayName;
        }

        var attribute2 = memberInfo.GetCustomAttribute<DevExpress.Xpo.DisplayNameAttribute>(false);
        if (attribute2 != null)
        {
            return attribute2.DisplayName;
        }

        var attribute3 = memberInfo.GetCustomAttribute<XafDisplayNameAttribute>(false);
        if (attribute3 != null)
        {
            return attribute3.DisplayName;
        }

        return null;
    }

    public static string GetDescription(this MemberInfo memberInfo)
    {
        return memberInfo.GetCustomAttribute<DescriptionAttribute>(false)?.Description;
    }

    public static string GetImageName(this MemberInfo memberInfo)
    {
        return memberInfo.GetCustomAttribute<ImageNameAttribute>(false)?.ImageName;
    }

    public static string GetCaptionFormat(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<ObjectCaptionFormatAttribute>(false)?.FormatString;
    }

    public static bool? GetIsPersistent(this IMemberInfo memberInfo)
    {
        if (memberInfo.FindAttribute<PersistentAttribute>(false) != null)
        {
            return true;
        }
        else if (memberInfo.FindAttribute<NonPersistentAttribute>(false) != null)
        {
            return false;
        }
        else
        {
            return null;
        }
    }

    public static string GetColumnName(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<PersistentAttribute>(false)?.MapTo;
    }

    public static string GetColumnDefaultValue(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<ColumnDefaultValueAttribute>(false)?.DefaultValue + string.Empty;
    }

    public static int? GetSize(this IMemberInfo memberInfo)
    {
        var size = memberInfo.FindAttribute<SizeAttribute>(false)?.Size;
        return size == 100 ? null : size;
    }

    public static bool? GetIsBrowsable(this IMemberInfo memberInfo)
    {
        var attribute = memberInfo.FindAttribute<BrowsableAttribute>(false);
        if (attribute != null)
        {
            return attribute.Browsable;
        }
        return null;
    }

    public static bool? GetIsVisibleInDetailView(this IMemberInfo memberInfo)
    {
        var attribute = memberInfo.FindAttribute<VisibleInDetailViewAttribute>(false);
        if (attribute != null)
        {
            return (bool)attribute.Value;
        }
        return null;
    }

    public static bool? GetIsVisibleInListView(this IMemberInfo memberInfo)
    {
        var attribute = memberInfo.FindAttribute<VisibleInListViewAttribute>(false);
        if (attribute != null)
        {
            return (bool)attribute.Value;
        }
        return null;
    }

    public static bool? GetIsVisibleInLookupListView(this IMemberInfo memberInfo)
    {
        var attribute = memberInfo.FindAttribute<VisibleInLookupListViewAttribute>(false);
        if (attribute != null)
        {
            return (bool)attribute.Value;
        }
        return null;
    }

    public static bool? GetIsVisibleInReports(this IMemberInfo memberInfo)
    {
        var attribute = memberInfo.FindAttribute<VisibleInReportsAttribute>(false);
        if (attribute != null)
        {
            return attribute.IsVisible;
        }
        return null;
    }

    public static bool GetIsPrimaryKey(this IMemberInfo memberInfo)
    {
        return memberInfo.IsKey;
    }

    public static bool? GetIsImmediatePost(this IMemberInfo memberInfo)
    {
        var attribute = memberInfo.FindAttribute<ImmediatePostDataAttribute>(false);
        if (attribute != null)
        {
            return (bool)attribute.Value;
        }
        return null;
    }

    public static bool? GetNoForeignKeyConstraints(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<NoForeignKeyAttribute>(false) != null ? true : null;
    }

    public static bool? GetIsEditable(this IMemberInfo memberInfo)
    {
        var attribute = memberInfo.FindAttributes<ModelDefaultAttribute>().FirstOrDefault(m => m.PropertyName == "AllowEdit");
        if (attribute != null)
        {
            var propertyValue = attribute.PropertyValue?.ToLowerInvariant();
            if (propertyValue == "true")
            {
                return true;
            }
            else if (propertyValue == "false")
            {
                return false;
            }
        }
        return null;
    }

    public static bool? GetIsCloneable(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<NonCloneableAttribute>(false) != null ? false : null;
    }

    public static bool GetHasAssociation(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<AssociationAttribute>(false) != null;
    }

    public static bool GetIsAggregated(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<DevExpress.Xpo.AggregatedAttribute>() != null
            || memberInfo.FindAttribute<DevExpress.ExpressApp.DC.AggregatedAttribute>() != null;
    }

    public static bool? GetIsFetchOnly(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<FetchOnlyAttribute>(false) != null ? true : null;
    }

    public static bool GetIsReadOnly(this IMemberInfo memberInfo)
    {
        return memberInfo.IsReadOnly;
    }

    public static bool? GetIsNullable(this IMemberInfo memberInfo)
    {
        return memberInfo.MemberType.IsGenericType && memberInfo.MemberType.GetGenericTypeDefinition() == typeof(Nullable<>) ? true : null;
    }

    public static string GetPropertyEditor(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<EditorAliasAttribute>()?.Alias;
    }

    public static string GetDataSourceCriteria(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<DataSourceCriteriaAttribute>()?.DataSourceCriteria;
    }

    public static string GetDataSourceCriteriaProperty(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<DataSourceCriteriaPropertyAttribute>()?.DataSourceCriteriaProperty;
    }

    public static string GetDataSourceProperty(this IMemberInfo memberInfo)
    {
        return memberInfo.FindAttribute<DataSourcePropertyAttribute>()?.DataSourceProperty;
    }

    public static PropertyType GetPropertyType(this IMemberInfo memberInfo)
    {
        return GetPropertyType(memberInfo.MemberType);
    }

    private static PropertyType GetPropertyType(Type type)
    {
        if (type == typeof(string))
        {
            return PropertyType.String;
        }
        else if (type == typeof(int))
        {
            return PropertyType.Integer;
        }
        else if (type == typeof(long))
        {
            return PropertyType.Long;
        }
        else if (type == typeof(float))
        {
            return PropertyType.Float;
        }
        else if (type == typeof(double))
        {
            return PropertyType.Double;
        }
        else if (type == typeof(decimal))
        {
            return PropertyType.Decimal;
        }
        else if (type == typeof(bool))
        {
            return PropertyType.Boolean;
        }
        else if (type == typeof(DateTime))
        {
            return PropertyType.DateTime;
        }
        else if (type == typeof(Guid))
        {
            return PropertyType.Guid;
        }
        else if (type == typeof(byte[]))
        {
            return PropertyType.Binary;
        }
        else if (type.IsEnum)
        {
            return PropertyType.Enumeration;
        }
        else if (typeof(PersistentBase).IsAssignableFrom(type))
        {
            return PropertyType.Entity;
        }
        else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(XPCollection<>))
        {
            return PropertyType.EntityCollection;
        }
        else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            return GetPropertyType(Nullable.GetUnderlyingType(type));
        }
        else
        {
            return PropertyType.Unknown;
        }
    }
}